// vue 进行的 webpack 的配置
'use strict'
const path = require('path')
const defaultSettings = require('./src/settings.js')

function resolve(dir) {
   return path.join(__dirname, dir)
}

const name = defaultSettings.title || 'vue Admin Template' // page title

// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
// port 端口
// process.env.port 实际就是一个nodejs下的环境变量
// .env.development和.env.production两个文件
// development => 开发环境

// production => 生产环境

// 当我们运行npm run dev进行开发调试的时候,此时会加载执行.env.development文件内容

// 当我们运行npm run build:prod进行生产环境打包的时候,会加载执行.env.production文件内容

// 所以,如果想要设置开发环境的接口,直接在.env.development中写入对于port变量的赋值即可
const port = process.env.port || process.env.npm_config_port || 9528 // dev port

// cdn 解释： 通过IP访问实际资源时，如果CDN上并没有缓存资源，则会到源站请求资源，并缓存到CDN节点上，
// 这样，用户下一次访问时，该CDN节点就会有对应资源的缓存了。
// CDN的基本原理是广泛采用各种缓存服务器,通过 CDN 引入的资源不会经 webpack 打包

// 会更加快速
let cdn = { css: [], js: [] }
let externals = {}
const isProd = process.env.NODE_ENV === 'production' // 判断是否是生产环境
// 通过环境变量 来区分是否使用cdn
if (isProd) {
   // 只有生产环境才有必要去做排除和 cdn 的注入
   externals = {
      'element-ui': 'ELEMENT',
      'xlsx': 'XLSX',
      'vue': 'Vue'
   }
   cdn = {
      css: [
         // element-ui css
         'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // 样式表
      ],
      js: [
         // vue must at first!
         // vue 必须放到首位
         'https://unpkg.com/vue/dist/vue.js', // vuejs
         // element-ui js
         'https://unpkg.com/element-ui/lib/index.js', // elementUI
         'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/jszip.min.js',
         'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/xlsx.full.min.js'
      ]
   }
}

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
   /**
    * You will need to set publicPath if you plan to deploy your site under a sub path,
    * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
    * then publicPath should be set to "/bar/".
    * In most cases please use '/' !!!
    * Detail: https://cli.vuejs.org/config/#publicpath
    */
   publicPath: '/',
   outputDir: 'dist',
   assetsDir: 'static',
   lintOnSave: process.env.NODE_ENV === 'development',
   productionSourceMap: false,
   devServer: {
      // 启动端口
      port: port,
      open: true,
      overlay: {
         warnings: false,
         errors: true
      },
      // 配置反向代理
      proxy: {
         // 当地址中有 /api 时，就会代理我们的请求地址向另外一个服务器发出请求，触发代理机制
         // 一旦写了 /api 就会把 /api ，包括 /api 的内容全都换到真正的 target 地址上
         // 这里的 key 也就是 /api 名字可以随便写，也可以写多个，意思是代理给多个
         // 例：意思就是一个项目可以跨很多域，很多服务器，当我的地址是 /api 到百度
         // /api1 到新浪 .......
         // '/api': {
         //    百度
         // },
         // '/api1': {
         //    新浪
         // },
         // '/api2': {
         //    腾讯
         // }
         '/api': {
            // vue-cli 服务器把路径改为下边的路径，返回时给我们页面
            // 要代理的服务器地址，不用写api,因为请求的地址中有 /api 就自动带上了
            // 因为请求头的基地址都加了一个 api
            // # base api
            // VUE_APP_BASE_API = '/api'
            // 我们并没有进行pathRewrite,因为后端接口就需要这个api
            // /api 前边换成我的域名，/api 会保留
            // : 冒号前边的 api 就替换了下边的 api，所以这里并没有写 api
            target: 'http://ihrm-java.itheima.net/',
            // 是否开启跨域
            changeOrigin: true
            // 重写路径，前提是不想要这个 /api
            // pathRewrite: {}
         }
         // 转换为：
         // http://localhost:8888/api/sys/login ==>
         // http://ihrm-java.itheima.net/api/sys/login
      }
      //  before: require('./mock/mock-server.js')
   },
   // 配置 webpack 的属性
   configureWebpack: {
      // provide the app's title in webpack's name field, so that
      // it can be accessed in index.html to inject the correct title.
      name: name,
      resolve: {
         alias: {
            '@': resolve('src')
         }
      },
      // 要排除的包名，排除打包的属性
      // key （要排除的包名）：value（实际上是实际引入的包的全局的变量名）
      // value 值实际就是 cdn 引入进来的
      // 因为要排除 element-ui 所以后边要引入 cnd 的文件，cdn 文件中油 element-ui 的全局变量名
      // externals  首先会排除掉定义的包名，空出来的位置会用变量来替换
      // 排除掉的三个包要用 cdn 的方式引入进来

      // 打包完之后，所有的导入的 js 会集中在一个 js 文件夹中，有一个总文件，还有其他按需加载进来的文件

      // 可以去查看 vue-element-admin  ---> 进阶 ---> cnd

      externals: externals
   },
   chainWebpack(config) {
      // it can improve the speed of the first screen, it is recommended to turn on preload
      config.plugin('preload').tap(() => [
         {
            rel: 'preload',
            // to ignore runtime.js
            // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
            fileBlacklist: [
               /\.map$/,
               /hot-update\.js$/,
               /runtime\..*\.js$/
            ],
            include: 'initial'
         }
      ])

      // 文件不是大吗？我们就不要把这些大的文件和那些小的文件打包到一起了，
      // 像这种xlsx, element这种功能性很全的插件，我们可以放到CDN服务器上，
      // 一来，减轻整体包的大小，二来CDN的加速服务可以加快我们对于插件的访问速度
      // 注入 cnd 变量
      // 这行代码会在执行打包的时候执行，就会把 cdn 变量注入到 html 模板中
      config.plugin('html').tap((args) => {
         // args 是注入 html 的一个变量
         // 后边的 cdn 就是定义的变量
         args[0].cdn = cdn
         // 返回这个参数
         return args
      })

      // when there are many pages, it will cause too many meaningless requests
      config.plugins.delete('prefetch')

      // set svg-sprite-loader
      config.module
         .rule('svg')
         .exclude.add(resolve('src/icons'))
         .end()
      config.module
         .rule('icons')
         .test(/\.svg$/)
         .include.add(resolve('src/icons'))
         .end()
         .use('svg-sprite-loader')
         .loader('svg-sprite-loader')
         .options({
            symbolId: 'icon-[name]'
         })
         .end()

      config.when(process.env.NODE_ENV !== 'development', config => {
         config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [
               {
                  // `runtime` must same as runtimeChunk name. default is `runtime`
                  inline: /runtime\..*\.js$/
               }
            ])
            .end()
         config.optimization.splitChunks({
            chunks: 'all',
            cacheGroups: {
               libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial' // only package third parties that are initially dependent
               },
               elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
               },
               commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
               }
            }
         })
         // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
         config.optimization.runtimeChunk('single')
      })
   }
}
